/*  RingBuffer
 *  For non-blocking IO. Inspired by cloudwu/mread
 *  Copyright (C) 2016 ZHANG X. <201560039@uibe.edu.cn>
 *   __ |  \   /   __| 
 *     /     /    |    
 *   ___|  _/ _\ \___| 
 *
 *  **All Rights Reserved**
 */
#ifndef RINGBUFFER_H
#define RINGBUFFER_H
#include <stdint.h>
#include <string.h>
#define INACTIVE_CONN UINT32_MAX
#define NO_SUCCEEDING UINT32_MAX
struct Ring_segment{
    uint32_t length;
    uint32_t connection;
    uint32_t next_sg;
    uint32_t conn_next;
};
/*  Caller allocate. */
struct Ring{
    uint32_t size;
    uint32_t tail;
    char buffer[];
};
#define RING_SEG_PTR(r, offset) ((struct Ring_segment *)((char*)(r)->buffer+(offset))) 
#define RING_SEG_DATA(r, offset) ((char *)(r)->buffer+(offset)+sizeof(struct Ring_segment))
#define RING_SEG_LEN(r, seg) (RING_SEG_PTR((r),(seg))->length)
#define RING_TAIL_BUFFER(r) RING_SEG_DATA((r),(r)->tail)
#define RING_TAIL_SIZE(r) RING_SEG_LEN((r), (r)->tail)
#define RING_CONN_NEXT(r, seg) (RING_SEG_PTR((r), (seg))->conn_next)
#define RING_SEG_CONN(r, seg) (RING_SEG_PTR((r), (seg))->connection)
inline void ring_init(struct Ring *r, uint32_t size){
    /*  Initialize entire buffer as a empty segment. */
    r->tail = 0;
    r->size = size;
    struct Ring_segment *tail = (struct Ring_segment *)r->buffer;
    /*  Length for data */
    tail->length = size - sizeof(struct Ring_segment);
    tail->connection = INACTIVE_CONN;
    tail->next_sg = r->tail;
    tail->conn_next = NO_SUCCEEDING;
}
uint32_t ring_drop_conn(struct Ring *, uint32_t *, uint32_t);
uint32_t ring_rearrange(struct Ring *, size_t);
void ring_link_conn(struct Ring *, uint32_t, uint32_t);
uint32_t ring_collect(struct Ring *, uint32_t, uint32_t);
uint32_t ring_next_conn(struct Ring *, uint32_t);
#endif /* RINGBUFFER_H */
